# -*- coding:utf-8 -*-

__author__ = 'zhaoxp'


import weakref


class Homework(object):

    def __init__(self):
        self._grade = 0

    @property
    def grade(self):
        return self._grade

    @grade.setter
    def grade(self,value):
        if not (0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100. but %s'%value)
        self._grade = value


class Exam0(object):
    def __init__(self):
        self._writing_grade = 0
        self._math_grade = 0

    @staticmethod
    def _check_grade(value):
        if not ( 0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100. but %s'%value)

    @property
    def writing_grade(self):
        return self._writing_grade

    @writing_grade.setter
    def writing_grade(self,value):
        self._check_grade(value)
        self._writing_grade = value
    
    @property
    def math_grade(self):
        return self._math_grade

    @math_grade.setter
    def math_grade(self,value):
        self._check_grade(value)
        self._math_grade = value
    
##############################################################################################

class Grade(object):
    def __init__(self):
        self._value = 0

    def __get__(self,instance,instance_type):
        return self._value

    def __set__(self,instance,value):
        if not ( 0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100. but %s'%value)
        self._value = value


class Exam(object):
    writing_grade = Grade()
    math_grade = Grade()


class Grade2(object):
    def __init__(self):
        self._value = {}

    def __get__(self,instance,instance_type):
        if instance is None:return self
        return self._value.get(instance,0)

    def __set__(self,instance,value):
        if not ( 0 <= value <= 100):
            raise ValueError('Grade must be between 0 and 100. but %s'%value)
        self._value[instance] = value


class Exam2(object):
    writing_grade = Grade2()
    math_grade = Grade2()


class Grade3(Grade2):
    def __init__(self):
        self._value = weakref.WeakKeyDictionary()


class Exam3(object):
    writing_grade = Grade3()
    math_grade = Grade3()


if __name__ == '__main__':
    print('Use Descriptor for Reusable @property Methods')
    h = Homework()
    h.grade = 93
    try:
        h.grade = -12
    except ValueError as ve:
        print('ValueError: %s'%ve)
    print('-'*30)
    e = Exam()
    e.writing_grade = 82
    e.math_grade = 93
    print('writing_grade = %s'%e.writing_grade)
    print('math_grade = %s'%e.math_grade)
    e2 = Exam()
    e2.writing_grade = 73
    print('e2.writing_grade = %s'%e2.writing_grade)
    print('e.writing_grade  = %s'%e.writing_grade)
    print('-'*30)
    ee = Exam2()
    ee.writing_grade = 82
    ee.math_grade = 93
    print('ee.writing_grade = %s'%ee.writing_grade)
    print('ee.math_grade = %s'%ee.math_grade)
    ee2 = Exam2()
    ee2.writing_grade = 63
    ee2.math_grade = 54
    print('ee.writing_grade = %s'%ee.writing_grade)
    print('ee.math_grade = %s'%ee.math_grade)
    print('ee2.writing_grade = %s'%ee2.writing_grade)
    print('ee2.math_grade = %s'%ee2.math_grade)
    print('-'*30)